package com.js.data.dtmg.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.js.data.common.exception.ApiException;
import com.js.data.common.utils.DateUtil;
import com.js.data.common.utils.ListUtil;
import com.js.data.dtmg.dto.DtTaskCronDto;
import com.js.data.dtmg.dto.DtTaskDto;
import com.js.data.dtmg.dto.DtTaskQuery;
import com.js.data.dtmg.entity.DtDatasource;
import com.js.data.dtmg.entity.DtTask;
import com.js.data.dtmg.mapper.DtTaskMapper;
import com.js.data.dtmg.mapper.SqlMapper;
import com.js.data.dtmg.quartz.QuartzJob;
import com.js.data.dtmg.service.DtDatasourceService;
import com.js.data.dtmg.service.DtTaskService;
import com.js.data.dtmg.util.DbUtil;
import com.js.data.dtmg.vo.DtTaskVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.sql.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * <p>
 * 任务表 服务实现类
 * </p>
 *
 * @author hh
 * @since 2024-07-17
 */
@Service
public class DtTaskServiceImpl extends ServiceImpl<DtTaskMapper, DtTask> implements DtTaskService {
     @Resource
    SqlMapper sqlMapper;
    @Resource
    DtDatasourceService datasourceService;
    @Resource
    PlatformTransactionManager transactionManager;
    @Resource
    QuartzJob quartzJob;

    /**
     * 分页查询
     *
     * @param query 查询条件
     * @return IPage<UserPageVO>
     */
    @Override
    public IPage<DtTaskVO> pageList(DtTaskQuery query) {
        Page<DtTask> inPage = new Page<>(query.getCurrent(), query.getSize());
        LambdaQueryWrapper<DtTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotEmpty(query.getTaskName()),DtTask::getTaskName,query.getTaskName());

        page(inPage,queryWrapper);
        IPage<DtTaskVO> retPage = new Page<>();
        BeanUtils.copyProperties(inPage, retPage);
        List<DtTask> records =  inPage.getRecords();
        retPage.setRecords(ListUtil.copyListToList(records,DtTaskVO.class));
        return retPage;
    }
    /**
     * 新增
     *
     * @param dto 表单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(DtTaskDto dto) {
        DtTask dtTask = new DtTask();
        BeanUtils.copyProperties(dto, dtTask);
        saveOrUpdate(dtTask);
        //创建ods表
        if(StringUtils.isNotEmpty(dtTask.getInData())){
            DbUtil.createOdsTableByTaskid(dto);
        }
        if(StringUtils.isNotEmpty(dtTask.getContent())){
            String proName = "doProcedureTask_"+dtTask.getId();
            sqlMapper.updateSql(" drop procedure if exists "+ proName);
            sqlMapper.updateSql("create procedure "+proName+dtTask.getContent());
        }

    }

    /**
     * 详情
     *
     * @param id      事项id
     */
    @Override
    public DtTaskVO detail(Long id){
        DtTask task =  getById(id);
        DtTaskVO vo = new DtTaskVO();
        BeanUtils.copyProperties(task,vo);
        return  vo;
    }
    /**
     * 删除
     *
     * @param id id
     */
    @Override
    public void delete(Long id) {
        DtTask task = getById(id);
        Optional.ofNullable(task).orElseThrow(() -> new ApiException("数据不存在"));
        if (!removeById(id)) {
            throw new ApiException("删除数据失败");
        }
    }
    @Override
    public Map<String,Object> doTask(DtTask task,String inTimeNo){
       DtDatasource dtDatasource = datasourceService.getById(task.getDtId());
       Map<String,Object> mapRtn = new HashMap<>();
       boolean errFlag = false;
       long inNum = 0L;
       if(StringUtils.isEmpty(inTimeNo)){
           inTimeNo = DateUtil.getDateTime() + task.getId();
       }
       //如果需要处理拉取数据
       if (StringUtils.isNotEmpty(task.getInData())) {
           //如果数据源是1mysql的
           if ("1".equals(dtDatasource.getDtType())) {
               mapRtn = doSqlInData(dtDatasource, task,inTimeNo);
           }

           String errMsg = (String)mapRtn.get("errMsg");
           if (StringUtils.isNotEmpty(errMsg)) {
               errFlag  = true;
           }else {
               inNum = Long.parseLong(String.valueOf(mapRtn.get("inNum")));
           }
       }
       //如果需要数据处理
       if (!errFlag && com.js.data.common.utils.StringUtils.isNotEmpty(task.getContent())) {
           mapRtn = DbUtil.callProcedure(task);
           mapRtn.put("inNum",inNum);
       }
        mapRtn.put("inTimeNo",inTimeNo);
        return mapRtn;
   }

    private Map<String,Object> doSqlInData(DtDatasource dtDatasource, DtTask task, String inTimeNo) {
        Map<String,Object> mapRtn = new HashMap<>();
        TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
        Connection conn = null;
        PreparedStatement preparedStatement = null;
        try {
            //删除本批次历史数据
            sqlMapper.updateSql(" delete from "+task.getOdsTableName()+ " where in_time_no='"+inTimeNo+"'");

            conn = DbUtil.getConn(dtDatasource);

            StringBuilder sqlBuilder = new StringBuilder();
            StringBuilder fieldBuilder = new StringBuilder();
            StringBuilder valueBuilder = new StringBuilder();
            int no =1,pageSize=10;
            long count = 0L;
            while ( no >0){
                String inSql = " select * from (" + DbUtil.covertSql(task.getInData(), task.getInParam()) + ") x limit "
                        +((no-1)*pageSize+1)+","+(no*pageSize);
                preparedStatement = conn.prepareStatement(inSql);
                ResultSet rs = preparedStatement.executeQuery();
                ResultSetMetaData resultSetMetaData = rs.getMetaData();
                int rsCount =0;
                while (rs.next()) {
                    sqlBuilder.setLength(0);
                    sqlBuilder.append(" insert into ").append(task.getOdsTableName()).append("(");
                    fieldBuilder.setLength(0);
                    valueBuilder.setLength(0);
                    for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
                        String colType = resultSetMetaData.getColumnTypeName(i).toLowerCase();
                        String fieldName = resultSetMetaData.getColumnName(i);
                        String value = rs.getString(fieldName);
                        fieldBuilder.append(fieldName).append(",");
                        if (value!=null && (colType.contains("char") || colType.contains("text") || colType.contains("json") || colType.contains("date"))) {
                            valueBuilder.append("'").append(value).append("',");
                        }else{
                            valueBuilder.append(value).append(",");
                        }
                    }
                    sqlBuilder.append(fieldBuilder).append("in_time_no) value(").append(valueBuilder)
                            .append("'").append(inTimeNo).append("')");
                    sqlMapper.updateSql(sqlBuilder.toString());

                    rsCount ++;
                }
                if(rsCount >=pageSize){
                    no ++;
                }else{
                    no = 0;
                }
                transactionManager.commit(transactionStatus);
                count += rsCount;
            }
            mapRtn.put("inNum",count);
        } catch (Exception ex) {
            mapRtn.put("errMsg",ex.getMessage());
            transactionManager.rollback(transactionStatus);
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException ignored) {}


        }
        return mapRtn;
    }

    /**
     * 新增
     *
     * @param dto 表单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveCron(DtTaskCronDto dto) {
        DtTask task = getById(dto.getId());
        BeanUtils.copyProperties(dto, task);
        updateById( task);
        //增加定时任务到任务
        //先删除现存定时任务
        quartzJob.removeTaskQuartzJob(dto.getId());
        if(StringUtils.isNotEmpty(dto.getCron())){
            quartzJob.addTaskQuartzJob(task);
        }
    }

}
